﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;

namespace HU8.Helpers.Files
{
    /// <summary>
    /// 站点配置助理.
    /// </summary>
    /// Author      Chiron
    public class WebConfiglHelper
    {
        private const string DefProviderName = "System.Data.SqlClient";

        /// <summary>
        /// 当前文档
        /// </summary>
        private XmlDocument doc;

        private const string curr = "/";
        private const string attr = "@";

        /// <summary>
        /// 配置节点名
        /// </summary>
        private const string configNode = "configuration";
        private const string sysWebNode = "system.web";

        private const string providersNode = "providers";


        private const string addNode = "add";

        private const string nameAttr = "name";
        private const string connStrAttr = "connectionString";
        private const string providerNameAttr = "providerName";

        private const string keyAttr = "key";
        private const string valueAttr = "value";
        private const string typeAttr = "type";
        private const string connStrNameAttr = "connectionStringName";
        private const string appNameAttr = "applicationName";

        /// <summary>
        /// 自动添加没有的节点
        /// </summary>
        public bool AutoAddNode { get { return autoAddNode; } set { autoAddNode = value; } }
        private bool autoAddNode = true;

        #region 错误提示信息
        /// <summary>
        /// 不能为空或NULL
        /// </summary>
        private const string errStringNotEmptyOrNULL = "不能为空或NULL!";
        #endregion

        #region 构造
        /// <summary>
        /// 从给定的 XmlDocument 对象中构造出站点配置助理.
        /// </summary>
        /// <param name="xmlDoc">XmlDocument 对象</param>
        public WebConfiglHelper(XmlDocument xmlDoc)
        {
            doc = xmlDoc;
        }

        /// <summary>
        /// 从指定的 URL 构造出站点配置助理.
        /// </summary>
        /// <param name="filename">文件的 URL，该文件包含要加载的 XML 文档。URL 既可以是本地文件，也可以是 HTTP URL（Web 地址）。</param>
        public WebConfiglHelper(string filename)
        {
            doc = new XmlDocument();
            doc.Load(filename);
        }
        #endregion

        #region 保存
        public void Save(string filename)
        {
            doc.Save(filename);
        }
        #endregion

        #region Helpers
        /// <summary>
        /// 取得指定实体节点
        /// </summary>
        /// <param name="nodeName">节点名</param>
        /// <param name="parentNode">父节点</param>
        /// <returns></returns>
        public XmlNode GetElement(string nodeName, XmlNode parentNode)
        {
            if (string.IsNullOrEmpty(nodeName)) throw new ArgumentException(errStringNotEmptyOrNULL, "nodeName");
            if (parentNode == null) throw new ArgumentNullException("parentNode");

            var node = parentNode.SelectSingleNode(nodeName);
            if (node == null && autoAddNode)
            {
                node = doc.CreateElement(nodeName);
                parentNode.AppendChild(node);
            }
            return node;
        }

        /// <summary>
        /// 取得指定实体节点的属性
        /// </summary>
        /// <param name="attrName">属性名</param>
        /// <param name="elementNode">实体节点</param>
        /// <returns></returns>
        public XmlAttribute GetAttribute(string attrName, XmlNode elementNode)
        {
            if (string.IsNullOrEmpty(attrName)) throw new ArgumentException(errStringNotEmptyOrNULL, "attrName");
            if (elementNode == null) throw new ArgumentNullException("elementNode");

            var attrNode = elementNode.SelectSingleNode(attr + attrName) as XmlAttribute;
            if (attrNode == null && autoAddNode)
            {
                attrNode = doc.CreateAttribute(attrName);
                elementNode.Attributes.Append(attrNode);
            }
            return attrNode;
        }

        /// <summary>
        /// 取得指定实体节点的属性值
        /// </summary>
        /// <param name="attrName">属性名</param>
        /// <param name="elementNode">实体节点</param>
        /// <returns></returns>
        public string GetAttributeValue(string attrName, XmlNode elementNode)
        {
            return GetAttribute(attrName, elementNode).Value;
        }

        /// <summary>
        /// 设置指定实体节点的属性值
        /// </summary>
        /// <param name="attrName">属性名</param>
        /// <param name="attrValue">属性值</param>
        /// <param name="elementNode">实体节点</param>
        /// <returns></returns>
        public XmlAttribute SetAttributeValue(string attrName, string attrValue, XmlNode elementNode)
        {
            var attr = GetAttribute(attrName, elementNode);
            attr.Value = attrValue;
            return attr;
        }

        /// <summary>
        /// 取得当前配置文档.
        /// </summary>
        /// <returns></returns>
        public XmlDocument GetDocument()
        {
            return doc;
        }

        /// <summary>
        /// 取得配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetConfigurationNode()
        {
            return GetElement(configNode, doc);
        }

        /// <summary>
        /// 取得网站配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetSystemWebNode()
        {
            return GetElement(sysWebNode, GetConfigurationNode());
        }

        /// <summary>
        /// 取得网络配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetSystemNetNode()
        {
            return GetElement(systemNetNode, GetConfigurationNode());
        }
        private const string systemNetNode = "system.net";

        /// <summary>
        /// 取得 Http 运行时节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetHttpRuntimeNode()
        {
            return GetElement(httpRuntimeNode, GetSystemWebNode());
        }
        private const string httpRuntimeNode = "httpRuntime";

        #endregion

        /// <summary>
        /// 脱机状态
        /// </summary>
        public bool OffLine
        {
            get
            {
                bool rv;
                bool.TryParse(GetAttributeValue(enabledAttr, GetHttpRuntimeNode()), out rv);
                return rv;
            }
            set
            {
                SetAttributeValue(enabledAttr, value.ToString(), GetHttpRuntimeNode());
            }
        }

        #region 数据库连接配置
        /// <summary>
        /// 数据库连接配置节点名
        /// </summary>
        private const string connNode = "connectionStrings";

        /// <summary>
        /// 取得数据库连接配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetConnectionStringsNode()
        {
            if (connectionStringsNode == null)
            {
                connectionStringsNode = GetElement(connNode, GetConfigurationNode());
            }

            return connectionStringsNode;
        }
        private XmlNode connectionStringsNode;

        /// <summary>
        /// 取得所有数据库连接配置
        /// </summary>
        /// <returns></returns>
        public IEnumerable<string> GetConnectionStrings()
        {
            return GetConnectionStringsNode().SelectNodes(addNode).Cast<XmlNode>().Select(d =>
                d.Attributes.Cast<XmlAttribute>().First(a => a.Name == nameAttr).Value);
        }

        /// <summary>
        /// 取得指定的数据库连接配置节点
        /// </summary>
        /// <param name="name">配置名</param>
        /// <returns></returns>
        public XmlNode GetConnectionStringNode(string name)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentException(errStringNotEmptyOrNULL, "name");
            var conn = GetConnectionStringsNode().SelectSingleNode(addNode + "[" + attr + nameAttr + "=\"" + name + "\"]");
            return conn;
        }


        /// <summary>
        /// 添加数据库连接配置
        /// </summary>
        /// <param name="name">配置名</param>
        /// <param name="connStr">数据库连接</param>
        /// <param name="providerName">提供程序名</param>
        public void AddConnectionString(string name, string connStr, string providerName = DefProviderName)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentException(errStringNotEmptyOrNULL, "name");
            if (string.IsNullOrEmpty(connStr)) throw new ArgumentException(errStringNotEmptyOrNULL, "connStr");
            if (string.IsNullOrEmpty(providerName)) throw new ArgumentException(errStringNotEmptyOrNULL, "providerName");

            if (GetConnectionStrings().Contains(name)) throw new ArgumentException(string.Format("已存在名为 {0} 的数据库连接!", name), "name");

            var connNode = GetConnectionStringsNode();
            var conn = doc.CreateElement(addNode);
            var aName = doc.CreateAttribute(nameAttr);
            var aConnStr = doc.CreateAttribute(connStrAttr);
            var aProviderName = doc.CreateAttribute(providerNameAttr);
            var attrs = conn.Attributes;
            attrs.Append(aName);
            attrs.Append(aConnStr);
            attrs.Append(aProviderName);
            connNode.AppendChild(conn);

            aConnStr.Value = connStr;
            aName.Value = name;
            aProviderName.Value = providerName;
        }

        /// <summary>
        /// 修改数据库连接配置
        /// </summary>
        /// <param name="oldName">配置名</param>
        /// <param name="newName">新配置名</param>
        /// <param name="connStr">数据库连接</param>
        /// <param name="providerName">提供程序名</param>
        public void SetConnectionString(string oldName, string newName, string connStr, string providerName = DefProviderName)
        {
            if (string.IsNullOrEmpty(oldName)) throw new ArgumentException(errStringNotEmptyOrNULL, "oldName");

            var conn = GetConnectionStringNode(oldName);
            if (conn == null) throw new ArgumentException(string.Format("不已存在名为 {0} 的数据库连接!", oldName), "oldName");

            if (!string.IsNullOrEmpty(newName))
            {
                if (GetConnectionStrings().Contains(newName)) throw new ArgumentException(string.Format("已存在名为 {0} 的数据库连接!", newName), "newName");
                conn.SelectSingleNode(attr + nameAttr).Value = newName;
            }

            if (!string.IsNullOrEmpty(connStr))
            {
                conn.SelectSingleNode(attr + connStrAttr).Value = connStr;
            }

            if (!string.IsNullOrEmpty(providerName))
            {
                conn.SelectSingleNode(attr + providerNameAttr).Value = providerName;
            }
        }

        /// <summary>
        /// 删除数据库连接配置
        /// </summary>
        /// <param name="name">配置名</param>
        public void RemoveConnectionString(string name)
        {
            var conn = GetConnectionStringNode(name);
            if (conn == null) throw new ArgumentException(string.Format("不存在名为 {0} 的数据库连接配置!", name), "name");
            GetConnectionStringsNode().RemoveChild(conn);
        }
        #endregion

        #region 程序设置配置
        private const string appSetsNode = "appSettings";

        /// <summary>
        /// 取得程序设置配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetAppSettingsNode()
        {
            return GetElement(appSetsNode, GetConfigurationNode());
        }

        /// <summary>
        /// 取得所有程序设置配置
        /// </summary>
        /// <returns></returns>
        public IEnumerable<string> GetAppSettings()
        {
            return GetAppSettingsNode().SelectNodes(addNode).Cast<XmlNode>().Select(d =>
                d.Attributes.Cast<XmlAttribute>().First(a => a.Name == keyAttr).Value);
        }

        /// <summary>
        /// 取得指定的程序设置节点
        /// </summary>
        /// <param name="key">配置键</param>
        /// <returns></returns>
        public XmlNode GetAppSettingNode(string key)
        {
            if (string.IsNullOrEmpty(key)) throw new ArgumentException(errStringNotEmptyOrNULL, "key");
            var appSet = GetAppSettingsNode().SelectSingleNode(addNode + "[" + attr + keyAttr + "=\"" + key + "\"]");
            return appSet;
        }

        /// <summary>
        /// 添加程序设置
        /// </summary>
        /// <param name="key">配置键</param>
        /// <param name="value">配置值</param>
        public void AddAppSetting(string key, string value)
        {
            if (string.IsNullOrEmpty(key)) throw new ArgumentException(errStringNotEmptyOrNULL, "name");
            if (value == null) value = string.Empty;

            if (GetAppSettings().Contains(key)) throw new ArgumentException(string.Format("已存在键为 {0} 的程序设置!", key), "key");

            var appSetsNode = GetAppSettingsNode();
            var appSet = doc.CreateElement(addNode);
            var aKey = doc.CreateAttribute(keyAttr);
            var aValue = doc.CreateAttribute(valueAttr);
            var attrs = appSet.Attributes;
            attrs.Append(aKey);
            attrs.Append(aValue);
            appSetsNode.AppendChild(appSet);

            aValue.Value = value;
            aKey.Value = key;
        }

        /// <summary>
        /// 修改程序设置
        /// </summary>
        /// <param name="oldKey">配置键</param>
        /// <param name="newKey">新配置键</param>
        /// <param name="value">配置值</param>
        public void SetAppSetting(string oldKey, string newKey, string value)
        {
            if (string.IsNullOrEmpty(oldKey)) throw new ArgumentException(errStringNotEmptyOrNULL, "oldKey");

            var appSet = GetAppSettingNode(oldKey);
            if (appSet == null) throw new ArgumentException(string.Format("不已存在键为 {0} 的程序设置!", oldKey), "oldKey");

            if (!string.IsNullOrEmpty(newKey))
            {
                if (GetAppSettings().Contains(newKey)) throw new ArgumentException(string.Format("已存在键为 {0} 的程序设置!", newKey), "newKey");
                appSet.SelectSingleNode(attr + keyAttr).Value = newKey;
            }

            if (value != null)
            {
                appSet.SelectSingleNode(attr + valueAttr).Value = value;
            }
        }

        /// <summary>
        /// 删除程序设置
        /// </summary>
        /// <param name="key">配置键</param>
        public void RemoveAppSetting(string key)
        {
            var appSet = GetAppSettingNode(key);
            if (appSet == null) throw new ArgumentException(string.Format("不存在键为 {0} 的程序设置!", key), "key");
            GetAppSettingsNode().RemoveChild(appSet);
        }
        #endregion

        #region 编译节点的配置
        private const string compNode = "compilation";
        private const string tarFrameworkAttr = "targetFramework";
        private const string debugAttr = "debug";

        /// <summary>
        /// 取得编译节点的配置
        /// </summary>
        /// <returns></returns>
        public XmlNode GetCompilationNode()
        {
            return GetElement(compNode, GetSystemWebNode());
        }

        /// <summary>
        /// 调试模式
        /// </summary>
        public bool Debug
        {
            get
            {
                bool rv;
                bool.TryParse(GetAttributeValue(debugAttr, GetCompilationNode()), out rv);
                return rv;
            }
            set
            {
                SetAttributeValue(debugAttr, value.ToString().ToLower(), GetCompilationNode());
            }
        }

        /// <summary>
        /// 目标框架
        /// </summary>
        public string TargetFramework
        {
            get
            {
                return GetAttributeValue(tarFrameworkAttr, GetCompilationNode());
            }
            set
            {
                SetAttributeValue(tarFrameworkAttr, value, GetCompilationNode());
            }
        }
        #endregion

        #region SMTP 设置
        /// <summary>
        /// 取得邮箱配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetMailSettingsNode()
        {
            return GetElement(mailSettingsNode, GetSystemNetNode());
        }
        private const string mailSettingsNode = "mailSettings";

        /// <summary>
        /// 取得Smtp配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetSmtpNode()
        {
            return GetElement(smtpNode, GetMailSettingsNode());
        }
        private const string smtpNode = "smtp";

        /// <summary>
        /// 发件人
        /// </summary>
        public string SmtpFrom
        {
            get
            {
                return GetAttributeValue(fromAttr, GetSmtpNode());
            }
            set
            {
                SetAttributeValue(fromAttr, value, GetSmtpNode());
            }
        }
        private const string fromAttr = "from";

        /// <summary>
        /// 取得 Smtp 的网络配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetSmtpNetworkNode()
        {
            return GetElement(networkNode, GetSmtpNode());
        }
        private const string networkNode = "network";

        /// <summary>
        /// Smtp 使用默认凭证
        /// </summary>
        public bool SmtpDefaultCredentials
        {
            get
            {
                bool rv;
                bool.TryParse(GetAttributeValue(defaultCredentialsAttr, GetSmtpNetworkNode()), out rv);
                return rv;
            }
            set
            {
                SetAttributeValue(defaultCredentialsAttr, value.ToString().ToLower(), GetSmtpNetworkNode());
            }
        }
        private const string defaultCredentialsAttr = "defaultCredentials";

        /// <summary>
        /// 服务器名
        /// </summary>
        public string SmtpHost
        {
            get
            {
                return GetAttributeValue(hostAttr, GetSmtpNetworkNode());
            }
            set
            {
                SetAttributeValue(hostAttr, value, GetSmtpNetworkNode());
            }
        }
        private const string hostAttr = "host";

        /// <summary>
        /// 服务器端口
        /// </summary>
        public int SmtpPort
        {
            get
            {
                int rv;
                int.TryParse(GetAttributeValue(portAttr, GetSmtpNetworkNode()), out rv);
                if (rv < 1) rv = 25;
                return rv;
            }
            set
            {
                if (value < 1) throw new ArgumentException("端口号不能小于 1 !");
                SetAttributeValue(portAttr, value.ToString(), GetSmtpNetworkNode());
            }
        }
        private const string portAttr = "port";

        /// <summary>
        /// 发件人账号
        /// </summary>
        public string SmtpUserName
        {
            get
            {
                return GetAttributeValue(userNameAttr, GetSmtpNetworkNode());
            }
            set
            {
                SetAttributeValue(userNameAttr, value, GetSmtpNetworkNode());
            }
        }
        private const string userNameAttr = "userName";

        /// <summary>
        /// 发件人密码
        /// </summary>
        public string SmtpPassword
        {
            get
            {
                return GetAttributeValue(passwordAttr, GetSmtpNetworkNode());
            }
            set
            {
                SetAttributeValue(passwordAttr, value, GetSmtpNetworkNode());
            }
        }
        private const string passwordAttr = "password";

        #endregion

        #region 认证配置
        private const string authNode = "authentication";
        private const string authModeAttr = "mode";


        /// <summary>
        /// 取得认证配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetAuthenticationNode()
        {
            return GetElement(authNode, GetSystemWebNode());
        }

        /// <summary>
        /// 认证模式
        /// </summary>
        public string AuthenticationMode
        {
            get
            {
                return GetAttributeValue(authModeAttr, GetAuthenticationNode());
            }
            set
            {
                SetAttributeValue(authModeAttr, value, GetAuthenticationNode());
            }
        }

        #region 表单认证配置
        private const string formsNode = "forms";
        private const string loginUrlAttr = "loginUrl";
        /// <summary>
        /// 取得表单认证配置
        /// </summary>
        /// <returns></returns>
        public XmlNode GetFormsNode()
        {
            return GetElement(formsNode, GetSystemWebNode());
        }

        /// <summary>
        /// 登录页面
        /// </summary>
        public string LoginUrl
        {
            get
            {
                return GetAttributeValue(loginUrlAttr, GetFormsNode());
            }
            set
            {
                SetAttributeValue(loginUrlAttr, value, GetFormsNode());
            }
        }
        #endregion

        #endregion

        #region 错误配置
        /// <summary>
        /// 取得错误配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetCustomErrorsNode()
        {
            return GetElement(customErrorsNode, GetSystemWebNode());
        }
        private const string customErrorsNode = "customErrors";

        /// <summary>
        /// 默认错误页面
        /// </summary>
        public string CustomErrorDefaultRedirect
        {
            get
            {
                return GetAttributeValue(defaultRedirectAttr, GetCustomErrorsNode());
            }
            set
            {
                SetAttributeValue(defaultRedirectAttr, value, GetCustomErrorsNode());
            }
        }
        private const string defaultRedirectAttr = "defaultRedirect";

        /// <summary>
        /// 错误处理模式
        /// </summary>
        public string CustomErrorMode
        {
            get
            {
                return GetAttributeValue(modeAttr, GetCustomErrorsNode());
            }
            set
            {
                SetAttributeValue(modeAttr, value, GetCustomErrorsNode());
            }
        }
        private const string modeAttr = "mode";

        /// <summary>
        /// 取得当然已配置的错误.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<string> GetCustomErrors()
        {
            return GetCustomErrorsNode().SelectNodes(errorNode + attr + statusCodeAttr).Cast<XmlAttribute>()
                .Select(d => d.Value);
        }
        private const string errorNode = "error";
        private const string statusCodeAttr = "statusCode";

        /// <summary>
        /// 取得指定的错误配置节点
        /// </summary>
        /// <param name="statusCode"></param>
        /// <returns></returns>
        public XmlNode GetCustomErrorNode(string statusCode)
        {
            if (string.IsNullOrEmpty(statusCode)) throw new ArgumentException(errStringNotEmptyOrNULL, "statusCode");

            return GetCustomErrorsNode().SelectSingleNode(errorNode + "[" + attr + statusCodeAttr + "='" + statusCode + "']");
        }

        /// <summary>
        /// 添加新的错误配置
        /// </summary>
        /// <param name="statusCode">错误代码</param>
        /// <param name="redirect">页面路径</param>
        public void AddCustomError(string statusCode, string redirect)
        {
            if (string.IsNullOrEmpty(statusCode)) throw new ArgumentException(errStringNotEmptyOrNULL, "statusCode");
            if (string.IsNullOrEmpty(redirect)) throw new ArgumentException(errStringNotEmptyOrNULL, "redirect");

            if (GetCustomErrors().Contains(statusCode)) throw new ArgumentException(string.Format("已存在错误代码为 {0} 的配置!", statusCode), "statusCode");

            var err = doc.CreateElement(errorNode);
            SetAttributeValue(statusCodeAttr, statusCode, err);
            SetAttributeValue(redirectAttr, redirect, err);
            GetCustomErrorsNode().AppendChild(err);

        }
        private const string redirectAttr = "redirect";

        /// <summary>
        /// 编辑指定的错误配置
        /// </summary>
        /// <param name="oldStatusCode">错误代码</param>
        /// <param name="newStatusCode">新的错误代码</param>
        /// <param name="redirect">页面路径</param>
        public void SetCustomError(string oldStatusCode, string newStatusCode, string redirect)
        {
            if (string.IsNullOrEmpty(oldStatusCode)) throw new ArgumentException(errStringNotEmptyOrNULL, "oldStatusCode");
            var err = GetCustomErrorNode(oldStatusCode);
            if (err == null) throw new ArgumentException(string.Format("找不到错误代码为 {0} 的配置!", oldStatusCode), "oldStatusCode");

            if (!string.IsNullOrEmpty(newStatusCode))
            {
                SetAttributeValue(statusCodeAttr, newStatusCode, err);
            }

            if (!string.IsNullOrEmpty(redirect))
            {
                SetAttributeValue(redirectAttr, redirect, err);
            }
        }

        /// <summary>
        /// 删除指定的错误配置
        /// </summary>
        /// <param name="statusCode"></param>
        public void RemoveCustomError(string statusCode)
        {
            if (string.IsNullOrEmpty(statusCode)) throw new ArgumentException(errStringNotEmptyOrNULL, "statusCode");
            var err = GetCustomErrorNode(statusCode);
            if (err == null) throw new ArgumentException(string.Format("找不到错误代码为 {0} 的配置!", statusCode), "statusCode");
            GetCustomErrorsNode().RemoveChild(err);
        }

        #endregion

        #region Membership
        /// <summary>
        /// 取得 Membership 配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetMembershipNode()
        {
            return GetElement(membershipNode, GetSystemWebNode());
        }
        private const string membershipNode = "membership";

        /// <summary>
        /// Membership 默认提供程序
        /// </summary>
        public string MembershipDefaultProvider
        {
            get
            {
                return GetAttributeValue(defaultProviderAttr, GetMembershipNode());
            }
            set
            {
                SetAttributeValue(defaultProviderAttr, value, GetMembershipNode());
            }
        }
        private const string defaultProviderAttr = "defaultProvider";

        /// <summary>
        /// Membership 检查用户是否在线的时间间隔(单位:分钟)
        /// </summary>
        public int MembershipUserIsOnlineTimeWindow
        {
            get
            {
                int rv;
                int.TryParse(GetAttributeValue(userIsOnlineTimeWindowAttr, GetMembershipNode()), out rv);
                if (rv == 0) rv = 30;
                return rv;
            }
            set
            {
                if (value < 1) throw new ArgumentException("不能小于1!");
                SetAttributeValue(userIsOnlineTimeWindowAttr, value.ToString(), GetMembershipNode());
            }
        }
        private const string userIsOnlineTimeWindowAttr = "userIsOnlineTimeWindow";

        /// <summary>
        /// 取得 Membership 提供程序配置集节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetMembershipProvidersNode()
        {
            return GetElement(providersNode, GetMembershipNode());
        }

        /// <summary>
        /// 取得所有 Membership 提供程序配置
        /// </summary>
        /// <returns></returns>
        public IEnumerable<string> GetMembershipProviders()
        {
            return GetMembershipProvidersNode().SelectNodes(addNode).Cast<XmlNode>().Select(d =>
                d.Attributes.Cast<XmlAttribute>().First(a => a.Name == nameAttr).Value);
        }

        /// <summary>
        /// 取得指定 Membership 提供程序配置节点
        /// </summary>
        /// <param name="name">配置名</param>
        /// <returns></returns>
        public XmlNode GetMembershipProvider(string name)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentException(errStringNotEmptyOrNULL, "name");
            var provider = GetMembershipProvidersNode().SelectSingleNode(addNode + "[" + attr + nameAttr + "=\"" + name + "\"]");
            return provider;
        }

        /// <summary>
        /// 添加 Membership 提供程序配置节点
        /// </summary>
        /// <param name="name">配置名</param>
        /// <param name="connStrName">数据库连接名</param>
        /// <param name="type">提供程序类型</param>
        /// <param name="appName">程序名</param>
        public void AddMembershipProvider(string name, string connStrName, string type = mbsp_defProviderType, string appName = "/")
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentException(errStringNotEmptyOrNULL, "name");
            if (string.IsNullOrEmpty(connStrName)) throw new ArgumentException(errStringNotEmptyOrNULL, "connStrName");
            if (string.IsNullOrEmpty(type)) throw new ArgumentException(errStringNotEmptyOrNULL, "type");
            if (string.IsNullOrEmpty(appName)) throw new ArgumentException(errStringNotEmptyOrNULL, "appName");

            if (GetMembershipProviders().Contains(name)) throw new ArgumentException(string.Format("已存在名为 {0} 的提供程序配置!", name), "name");

            var providersNode = GetMembershipProvidersNode();
            var provider = doc.CreateElement(addNode);
            providersNode.AppendChild(provider);

            SetAttributeValue(nameAttr, name, provider);
            SetAttributeValue(connStrNameAttr, connStrName, provider);
            SetAttributeValue(typeAttr, type, provider);
            SetAttributeValue(appNameAttr, appName, provider);
        }

        /// <summary>
        /// 修改 Membership 提供程序配置
        /// </summary>
        /// <param name="oldName">配置名</param>
        /// <param name="newName">新配置名</param>
        /// <param name="connStrName">数据库连接名</param>
        /// <param name="type">提供程序类型</param>
        /// <param name="appName">程序名</param>
        public void SetMembershipProvider(string oldName, string newName, string connStrName, string type = mbsp_defProviderType, string appName = "/")
        {
            if (string.IsNullOrEmpty(oldName)) throw new ArgumentException(errStringNotEmptyOrNULL, "oldName");

            var provider = GetMembershipProvider(oldName);
            if (provider == null) throw new ArgumentException(string.Format("不已存在名为 {0} 的提供程序配置!", oldName), "oldName");

            if (!string.IsNullOrEmpty(newName))
            {
                if (GetMembershipProviders().Contains(newName)) throw new ArgumentException(string.Format("已存在名为 {0} 的提供程序配置!", newName), "newName");
                SetAttributeValue(nameAttr, newName, provider);
            }

            if (!string.IsNullOrEmpty(connStrName))
            {
                SetAttributeValue(connStrName, connStrName, provider);
            }
            if (!string.IsNullOrEmpty(type))
            {
                SetAttributeValue(typeAttr, type, provider);
            }
            if (!string.IsNullOrEmpty(appName))
            {
                SetAttributeValue(appNameAttr, appName, provider);
            }

        }
        private const string mbsp_defProviderType = "System.Web.Security.SqlMembershipProvider";

        /// <summary>
        /// 删除 Membership 提供程序配置
        /// </summary>
        /// <param name="name">配置名</param>
        public void RemoveMembershipProvider(string name)
        {
            var provider = GetMembershipProvider(name);
            if (provider == null) throw new ArgumentException(string.Format("不存在名为 {0} 的提供程序配置!", name), "name");
            GetMembershipProvidersNode().RemoveChild(provider);
        }
        #endregion

        #region Profile
        /// <summary>
        /// 取得 Profile 配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetProfileNode()
        {
            return GetElement(profileNode, GetSystemWebNode());
        }
        private const string profileNode = "profile";

        /// <summary>
        /// Profile 默认提供程序
        /// </summary>
        public string ProfileDefaultProvider
        {
            get
            {
                return GetAttributeValue(defaultProviderAttr, GetProfileNode());
            }
            set
            {
                SetAttributeValue(defaultProviderAttr, value, GetProfileNode());
            }
        }

        /// <summary>
        /// 启用 Profile
        /// </summary>
        public bool ProfileEnabled
        {
            get
            {
                bool rv;
                bool.TryParse(GetAttributeValue(enabledAttr, GetProfileNode()), out rv);
                return rv;
            }
            set
            {
                SetAttributeValue(enabledAttr, value.ToString().ToLower(), GetProfileNode());
            }
        }
        private const string enabledAttr = "enabled";

        /// <summary>
        /// 取得 Profile 提供程序配置集节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetProfileProvidersNode()
        {
            return GetElement(providersNode, GetProfileNode());
        }

        /// <summary>
        /// 取得所有 Profile 提供程序配置
        /// </summary>
        /// <returns></returns>
        public IEnumerable<string> GetProfileProviders()
        {
            return GetProfileProvidersNode().SelectNodes(addNode).Cast<XmlNode>().Select(d =>
                d.Attributes.Cast<XmlAttribute>().First(a => a.Name == nameAttr).Value);
        }

        /// <summary>
        /// 取得指定 Profile 提供程序配置节点
        /// </summary>
        /// <param name="name">配置名</param>
        /// <returns></returns>
        public XmlNode GetProfileProvider(string name)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentException(errStringNotEmptyOrNULL, "name");
            var provider = GetProfileProvidersNode().SelectSingleNode(addNode + "[" + attr + nameAttr + "=\"" + name + "\"]");
            return provider;
        }

        /// <summary>
        /// 添加 Profile 提供程序配置节点
        /// </summary>
        /// <param name="name">配置名</param>
        /// <param name="connStrName">数据库连接名</param>
        /// <param name="type">提供程序类型</param>
        /// <param name="appName">程序名</param>
        public void AddProfileProvider(string name, string connStrName, string type = p_defProviderType, string appName = "/")
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentException(errStringNotEmptyOrNULL, "name");
            if (string.IsNullOrEmpty(connStrName)) throw new ArgumentException(errStringNotEmptyOrNULL, "connStrName");
            if (string.IsNullOrEmpty(type)) throw new ArgumentException(errStringNotEmptyOrNULL, "type");
            if (string.IsNullOrEmpty(appName)) throw new ArgumentException(errStringNotEmptyOrNULL, "appName");

            if (GetProfileProviders().Contains(name)) throw new ArgumentException(string.Format("已存在名为 {0} 的提供程序配置!", name), "name");

            var providersNode = GetProfileProvidersNode();
            var provider = doc.CreateElement(addNode);
            providersNode.AppendChild(provider);

            SetAttributeValue(nameAttr, name, provider);
            SetAttributeValue(connStrNameAttr, connStrName, provider);
            SetAttributeValue(typeAttr, type, provider);
            SetAttributeValue(appNameAttr, appName, provider);
        }

        /// <summary>
        /// 修改 Profile 提供程序配置
        /// </summary>
        /// <param name="oldName">配置名</param>
        /// <param name="newName">新配置名</param>
        /// <param name="connStrName">数据库连接名</param>
        /// <param name="type">提供程序类型</param>
        /// <param name="appName">程序名</param>
        public void SetProfileProvider(string oldName, string newName, string connStrName, string type = p_defProviderType, string appName = "/")
        {
            if (string.IsNullOrEmpty(oldName)) throw new ArgumentException(errStringNotEmptyOrNULL, "oldName");

            var provider = GetProfileProvider(oldName);
            if (provider == null) throw new ArgumentException(string.Format("不已存在名为 {0} 的提供程序配置!", oldName), "oldName");

            if (!string.IsNullOrEmpty(newName))
            {
                if (GetProfileProviders().Contains(newName)) throw new ArgumentException(string.Format("已存在名为 {0} 的提供程序配置!", newName), "newName");
                SetAttributeValue(nameAttr, newName, provider);
            }

            if (!string.IsNullOrEmpty(connStrName))
            {
                SetAttributeValue(connStrName, connStrName, provider);
            }
            if (!string.IsNullOrEmpty(type))
            {
                SetAttributeValue(typeAttr, type, provider);
            }
            if (!string.IsNullOrEmpty(appName))
            {
                SetAttributeValue(appNameAttr, appName, provider);
            }

        }
        private const string p_defProviderType = "System.Web.Profile.SqlProfileProvider";

        /// <summary>
        /// 删除 Profile 提供程序配置
        /// </summary>
        /// <param name="name">配置名</param>
        public void RemoveProfileProvider(string name)
        {
            var provider = GetProfileProvider(name);
            if (provider == null) throw new ArgumentException(string.Format("不存在名为 {0} 的提供程序配置!", name), "name");
            GetProfileProvidersNode().RemoveChild(provider);
        }
        #endregion

        #region RoleManager
        /// <summary>
        /// 取得 RoleManager 配置节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetRoleManagerNode()
        {
            return GetElement(roleManagerNode, GetSystemWebNode());
        }
        private const string roleManagerNode = "roleManager";

        /// <summary>
        /// RoleManager 默认提供程序
        /// </summary>
        public string RoleManagerDefaultProvider
        {
            get
            {
                return GetAttributeValue(defaultProviderAttr, GetRoleManagerNode());
            }
            set
            {
                SetAttributeValue(defaultProviderAttr, value, GetRoleManagerNode());
            }
        }

        /// <summary>
        /// 启用 RoleManager
        /// </summary>
        public bool RoleManagerEnabled
        {
            get
            {
                bool rv;
                bool.TryParse(GetAttributeValue(enabledAttr, GetRoleManagerNode()), out rv);
                return rv;
            }
            set
            {
                SetAttributeValue(enabledAttr, value.ToString().ToLower(), GetRoleManagerNode());
            }
        }

        /// <summary>
        /// 取得 RoleManager 提供程序配置集节点
        /// </summary>
        /// <returns></returns>
        public XmlNode GetRoleManagerProvidersNode()
        {
            return GetElement(providersNode, GetRoleManagerNode());
        }

        /// <summary>
        /// 取得所有 RoleManager 提供程序配置
        /// </summary>
        /// <returns></returns>
        public IEnumerable<string> GetRoleManagerProviders()
        {
            return GetRoleManagerProvidersNode().SelectNodes(addNode).Cast<XmlNode>().Select(d =>
                d.Attributes.Cast<XmlAttribute>().First(a => a.Name == nameAttr).Value);
        }

        /// <summary>
        /// 取得指定 RoleManager 提供程序配置节点
        /// </summary>
        /// <param name="name">配置名</param>
        /// <returns></returns>
        public XmlNode GetRoleManagerProvider(string name)
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentException(errStringNotEmptyOrNULL, "name");
            var provider = GetRoleManagerProvidersNode().SelectSingleNode(addNode + "[" + attr + nameAttr + "=\"" + name + "\"]");
            return provider;
        }

        /// <summary>
        /// 添加 RoleManager 提供程序配置节点
        /// </summary>
        /// <param name="name">配置名</param>
        /// <param name="connStrName">数据库连接名</param>
        /// <param name="type">提供程序类型</param>
        /// <param name="appName">程序名</param>
        public void AddRoleManagerProvider(string name, string connStrName, string type = rm_defProviderType, string appName = "/")
        {
            if (string.IsNullOrEmpty(name)) throw new ArgumentException(errStringNotEmptyOrNULL, "name");
            if (string.IsNullOrEmpty(connStrName)) throw new ArgumentException(errStringNotEmptyOrNULL, "connStrName");
            if (string.IsNullOrEmpty(type)) throw new ArgumentException(errStringNotEmptyOrNULL, "type");
            if (string.IsNullOrEmpty(appName)) throw new ArgumentException(errStringNotEmptyOrNULL, "appName");

            if (GetProfileProviders().Contains(name)) throw new ArgumentException(string.Format("已存在名为 {0} 的提供程序配置!", name), "name");

            var providersNode = GetRoleManagerProvidersNode();
            var provider = doc.CreateElement(addNode);
            providersNode.AppendChild(provider);

            SetAttributeValue(nameAttr, name, provider);
            SetAttributeValue(connStrNameAttr, connStrName, provider);
            SetAttributeValue(typeAttr, type, provider);
            SetAttributeValue(appNameAttr, appName, provider);
        }

        /// <summary>
        /// 修改 RoleManager 提供程序配置
        /// </summary>
        /// <param name="oldName">配置名</param>
        /// <param name="newName">新配置名</param>
        /// <param name="connStrName">数据库连接名</param>
        /// <param name="type">提供程序类型</param>
        /// <param name="appName">程序名</param>
        public void SetRoleManagerProvider(string oldName, string newName, string connStrName, string type = rm_defProviderType, string appName = "/")
        {
            if (string.IsNullOrEmpty(oldName)) throw new ArgumentException(errStringNotEmptyOrNULL, "oldName");

            var provider = GetRoleManagerProvider(oldName);
            if (provider == null) throw new ArgumentException(string.Format("不已存在名为 {0} 的提供程序配置!", oldName), "oldName");

            if (!string.IsNullOrEmpty(newName))
            {
                if (GetRoleManagerProviders().Contains(newName)) throw new ArgumentException(string.Format("已存在名为 {0} 的提供程序配置!", newName), "newName");
                SetAttributeValue(nameAttr, newName, provider);
            }

            if (!string.IsNullOrEmpty(connStrName))
            {
                SetAttributeValue(connStrName, connStrName, provider);
            }
            if (!string.IsNullOrEmpty(type))
            {
                SetAttributeValue(typeAttr, type, provider);
            }
            if (!string.IsNullOrEmpty(appName))
            {
                SetAttributeValue(appNameAttr, appName, provider);
            }

        }
        private const string rm_defProviderType = "System.Web.Security.SqlRoleProvider";

        /// <summary>
        /// 删除 RoleManager 提供程序配置
        /// </summary>
        /// <param name="name">配置名</param>
        public void RemoveRoleManagerProvider(string name)
        {
            var provider = GetRoleManagerProvider(name);
            if (provider == null) throw new ArgumentException(string.Format("不存在名为 {0} 的提供程序配置!", name), "name");
            GetRoleManagerProvidersNode().RemoveChild(provider);
        }
        #endregion
    }
}
